#include "Col.ph"
#ifdef __GNUG__
#pragma implementation
#endif

#include "ClassManager.h"

#include "Class.h"
#include "String.h"
#include "OrdColl.h"
#include "SortedOList.h"
#include "ObjectTable.h"
#include "System.h"
#include "ET_stdio.h"

ClassManager *gClassManager;

//---- ClassManager ------------------------------------------------------------

NewMetaImpl(ClassManager,Object, (TP(classTable), TB(sorted)));

ClassManager::ClassManager()
{
	classTable= 0;
	sorted= FALSE;
}

ClassManager::~ClassManager()
{
	SafeDelete(classTable);
}

//---- class table management --------------------------------------------------

OrdCollection *ClassManager::sortClassTable()
{
	if (classTable)
		classTable->Sort();
	sorted= TRUE;
	return classTable;
}

void ClassManager::Add(Class *cl)
{
	if (classTable == 0)
		classTable= new OrdCollection(400);
	if (classTable->FindPtr(cl) == 0)
		classTable->Add(cl);
	sorted= FALSE;
}

bool ClassManager::Remove(Class *cl)
{
	if (classTable && cl != 0 && classTable->RemovePtr(cl)) {
		if (gDebug)
			fprintf(stderr, "~%s\n", cl->Name());
		if (classTable->Size() <= 0) {
			Object *t= classTable;
			classTable= 0;
			SafeDelete(t);
		}
		return TRUE;
	}
	return FALSE;
}

Class *ClassManager::Find(const char *name, double version)
{
	Class lookFor(name, version);
	int at= GetClassTable()->BinarySearch(&lookFor);
	if (at != -1)
		return (Class*) GetClassTable()->At(at);
	return 0;
}

Class *ClassManager::FindOrLoad(const char *name, double version)
{
	Class *clp= Find(name, version);
	if (clp == 0 && gSystem) {
		gSystem->Load(name, 0);
		clp= Find(name, version);
		if (clp == 0)
			Error("FindOrLoad", "cannot load class %s", name);
	}
	return clp;
}

Object *ClassManager::Load(const char *module, const char *cla)
{
	Class *cl= gClassManager->Find(cla);
	if (cl == 0 && gSystem)
		gSystem->Load(module, 0);
	cl= gClassManager->Find(cla);
	if (cl == 0) {
		fprintf(stderr, "can't find class %s\n", cla);
		return 0;
	}
	return cl->Proto()->New();
}

void ClassManager::SetupSubclasses()
{
	OrdCollectionIter next(GetClassTable());
	register Class *clp, *super;

	while (clp= (Class*) next())
		if (clp->SubClasses())
			clp->SubClasses()->Empty();

	next.Reset();
	while (clp= (Class*) next())
		if (super= clp->Super())
			super->AddSubclass(clp);
}

OrdCollection *ClassManager::GetClassTable()
{
	return sorted ? classTable : sortClassTable();
}

Iterator *ClassManager::Iterator()
{
	return GetClassTable()->MakeIterator();
}

//---- sort list according to number of instances of a class -------------------

class CumSortedObjList : public SortedObjList {
public:
	CumSortedObjList()
		{ }
	int CompareObjects(Object*, Object*);
};

int CumSortedObjList::CompareObjects(Object *op1, Object *op2)
{
	return Guard(op2, Class)->GetInstanceCount() - Guard(op1, Class)->GetInstanceCount();
}

void ClassManager::InstanceStatistics(bool cumsorted)
{
	Class *clp;
	int cum= 0;
	Collection *col, *csl= 0;

	ObjectTable::UpdateInstCount(TRUE);
	if (cumsorted) {
		col= csl= new CumSortedObjList;
		csl->AddAll(classTable);
	} else
		col= GetClassTable();
	Iter next(col);

	fprintf(stderr, "Instances per class on heap\n");
	fprintf(stderr, "=============================\n");
	while (clp= (Class*) next()) {
		if (clp->GetInstanceCount() > 0) {
			fprintf(stderr, "%-20s%8d%8d\n", clp->Name(),
					clp->GetInstanceCount(), clp->Size());
			cum+= clp->GetInstanceCount();
		}
	}
	fprintf(stderr, "-----------------------------\n");
	fprintf(stderr, "Total %d\n", cum);
	fprintf(stderr, "=============================\n");

	SafeDelete(csl);
}

